package spring.data.jpa.config;

import java.lang.annotation.Annotation;

import javax.persistence.Entity;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.util.Streamable;

public class SimpleAnnotationRepositoryConfigurationSource extends AnnotationRepositoryConfigurationSource {

    private final ResourceLoader resourceLoader;

    private Environment environment;

    /**
     * Creates a new {@link SimpleAnnotationRepositoryConfigurationSource} from
     * the given {@link AnnotationMetadata} and annotation.
     * 
     * @param metadata
     *            must not be {@literal null}.
     * @param annotation
     *            must not be {@literal null}.
     * @param resourceLoader
     *            must not be {@literal null}.
     * @param environment
     */
    public SimpleAnnotationRepositoryConfigurationSource(AnnotationMetadata metadata,
            Class<? extends Annotation> annotation, ResourceLoader resourceLoader, Environment environment,
            BeanDefinitionRegistry registry) {
        super(metadata, annotation, resourceLoader, environment, registry);
        this.environment = environment;
        this.resourceLoader = resourceLoader;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.springframework.data.repository.config.RepositoryConfiguration#
     * getCandidates(org.springframework.context.annotation.
     * ClassPathScanningCandidateComponentProvider)
     */
    @Override
    public Streamable<BeanDefinition> getCandidates(ResourceLoader loader) {
        ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
        scanner.setEnvironment(this.environment);
        scanner.setResourceLoader(this.resourceLoader);
        /*Entity*/
        scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));

        getExcludeFilters().forEach(scanner::addExcludeFilter);

        return Streamable.of(() -> getBasePackages().stream()//
                .flatMap(it -> scanner.findCandidateComponents(it).stream()));
    }

}
